﻿// -----------------------------------------------------------------------
// <copyright file="HtmlHelperExtensions.cs" company="EPAM Systems">
////Copyright (c) EPAM Systems, 2012. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

namespace MBOP.Website.Helpers
{
	#region Usings

	using System;
	using System.Globalization;
	using System.Text;
	using System.Web.Mvc;

	using MBOP.Core.Entities.Common;
	using MBOP.Website.Resources;
	using MBOP.Website.ViewModels.Common;
	using MBOP.Website.ViewModels.Tooltips;
	using MBOP.Core.Entities.Library;

	#endregion

	/// <summary>
	/// Defines the extensions of html helper.
	/// </summary>
	public static class HtmlHelperExtensions
	{
		#region Constants

		/// <summary>
		/// Represents the html anchor tag name.
		/// </summary>
		private const string TAG_NAME_A = "a";

		/// <summary>
		/// Represents the span tag name.
		/// </summary>
		private const string TAG_NAME_SPAN = "span";

		/// <summary>
		/// Represents the sort text
		/// </summary>
		private const string CSS_CLASS_SORT_TEXT = "sortingText";

		/// <summary>
		/// Represents selected page's style class name.
		/// </summary>
		private const string CSS_CLASS_SELECTED = "selectedItem";

		/// <summary>
		/// Represents the icon style class name.
		/// </summary>
		private const string CSS_CLASS_ICON = "icon";

		/// <summary>
		/// Represents the sort cursor style class name.
		/// </summary>
		private const string CSS_CLASS_SORT_CURSOR = "sortingCursor";

		/// <summary>
		/// Represents the down cursor style class name.
		/// </summary>
		private const string CSS_CLASS_DOWN_SORT_CURSOR = "downCursorIcon";

		/// <summary>
		/// Represents the up cursor style class name.
		/// </summary>
		private const string CSS_CLASS_UP_SORT_CURSOR = "upCursorIcon";

		/// <summary>
		/// Represents reference attribute name.
		/// </summary>
		private const string HREF_ATTRIBUTE_NAME = "href";

		/// <summary>
		/// Represents the filter link separator.
		/// </summary>
		private const string FILTER_LINKS_SEPARATOR = "|";

		/// <summary>
		/// Represents the space string.
		/// </summary>
		private const string SPACE_STRING = " ";

		/// <summary>
		/// Represents the comma string.
		/// </summary>
		private const string COMMA_STRING = ",";

		#endregion

		#region Extensions

		/// <summary>
		/// Generates pages links.
		/// </summary>
		/// <param name="html">The extension class.</param>
		/// <param name="currentPage">The current page of the books.</param>
		/// <param name="pagesTotal">Total pages of the books.</param>
		/// <param name="pageUrl">The delegate, which generates text link to the page.</param>
		/// <returns>The html string, which contains pages links.</returns>
		public static MvcHtmlString GeneratePageLinks(this HtmlHelper html, int currentPage, int pagesTotal, Func<int, string> pageUrl)
		{
			const int OFFSET_PAGE = 1;

			TagBuilder dots = new TagBuilder(TAG_NAME_A);

			dots.SetInnerText("...");

			StringBuilder resultUrl = new StringBuilder();

			if (pagesTotal > (OFFSET_PAGE * 4) + 1)
			{
				if (currentPage < 1 + (OFFSET_PAGE * 3))
				{
					AppendPages(1, (OFFSET_PAGE * 3) + 1, currentPage, pagesTotal, resultUrl, pageUrl);

					resultUrl.AppendLine(dots.ToString());

					AppendPages(pagesTotal - OFFSET_PAGE + 1, pagesTotal, currentPage, pagesTotal, resultUrl, pageUrl);
				}
				else if (currentPage >= 1 + (OFFSET_PAGE * 3) && currentPage < pagesTotal - (OFFSET_PAGE * 2))
				{
					AppendPages(1, OFFSET_PAGE, currentPage, pagesTotal, resultUrl, pageUrl);

					resultUrl.AppendLine(dots.ToString());

					AppendPages(currentPage - OFFSET_PAGE, currentPage + OFFSET_PAGE, currentPage, pagesTotal, resultUrl, pageUrl);

					resultUrl.AppendLine(dots.ToString());

					AppendPages(pagesTotal - OFFSET_PAGE + 1, pagesTotal, currentPage, pagesTotal, resultUrl, pageUrl);
				}
				else
				{
					AppendPages(1, OFFSET_PAGE, currentPage, pagesTotal, resultUrl, pageUrl);

					resultUrl.AppendLine(dots.ToString());

					AppendPages(pagesTotal - (OFFSET_PAGE * 2) - 1, pagesTotal, currentPage, pagesTotal, resultUrl, pageUrl);
				}
			}
			else
			{
				AppendPages(1, pagesTotal, currentPage, pagesTotal, resultUrl, pageUrl);
			}

			return new MvcHtmlString(resultUrl.ToString());
		}

		/// <summary>
		/// Generates filter links.
		/// </summary>
		/// <param name="html">The extension class.</param>
		/// <param name="currentFilter">The current filter.</param>
		/// <param name="filterUrl">The delegate,  which generates link to the filter.</param>
		/// <returns>The html string, which contains filter links.</returns>
		public static MvcHtmlString GenerateFilterLinks(this HtmlHelper html, FilterType currentFilter, Func<FilterType, string> filterUrl)
		{
			StringBuilder resultLinks = new StringBuilder();

			string[] filterTypeNames = Enum.GetNames(typeof(FilterType));
			Array filterTypeValues = Enum.GetValues(typeof(FilterType));

			for (int enumIndex = 0; enumIndex < filterTypeNames.Length; enumIndex++)
			{
				TagBuilder tagA = new TagBuilder(TAG_NAME_A);

				if ((FilterType)filterTypeValues.GetValue(enumIndex) == currentFilter)
				{
					tagA.AddCssClass(CSS_CLASS_SELECTED);
				}

				tagA.MergeAttribute(HREF_ATTRIBUTE_NAME, filterUrl((FilterType)filterTypeValues.GetValue(enumIndex)));
				tagA.SetInnerText(filterTypeNames[enumIndex]);

				resultLinks.Append(tagA.ToString());

				if (enumIndex != filterTypeNames.Length - 1)
				{
					resultLinks.Append(string.Concat(SPACE_STRING, FILTER_LINKS_SEPARATOR, SPACE_STRING));
				}
			}

			return new MvcHtmlString(resultLinks.ToString());
		}

		/// <summary>
		/// Generates sort links.
		/// </summary>
		/// <param name="html">The extension class.</param>
		/// <param name="currentSortInfo">The current sorting info.</param>
		/// <param name="sortUrl">The delegate, which generates link to the filter.</param>
		/// <returns>The hmtl string, which contains sorting links.</returns>
		public static MvcHtmlString GenerateSortLinks(this HtmlHelper html, SortInfo currentSortInfo, Func<SortField,SortType, string> sortUrl)
		{
			StringBuilder resultLinks=new StringBuilder();

			string[] sortFieldNames = Enum.GetNames(typeof (SortField));
			Array sortFieldValues = Enum.GetValues(typeof (SortField));

			for (int enumIndex = 1; enumIndex < sortFieldNames.Length; enumIndex++)
			{
				TagBuilder tagA = new TagBuilder(TAG_NAME_A);

				TagBuilder sortCursorIconBuilder = null;

				SortType tagSortingType = SortType.Desc;

				if ((SortField)sortFieldValues.GetValue(enumIndex) == currentSortInfo.GetUnderlyingSortField())
				{
					tagA.AddCssClass(CSS_CLASS_SELECTED);

					sortCursorIconBuilder = GenerateCursorIcon(currentSortInfo.GetUnderlyingSortType());

					tagSortingType=currentSortInfo.GetUnderlyingSortType() == SortType.Asc ? SortType.Desc : SortType.Asc;
				}

				tagA.MergeAttribute(HREF_ATTRIBUTE_NAME, sortUrl((SortField)sortFieldValues.GetValue(enumIndex),tagSortingType));

				TagBuilder sortLinkContentBuilder=new TagBuilder(TAG_NAME_SPAN);

				sortLinkContentBuilder.AddCssClass(CSS_CLASS_SORT_TEXT);

				sortLinkContentBuilder.SetInnerText(sortFieldNames[enumIndex]);

				string cursorPart = sortCursorIconBuilder != null ? sortCursorIconBuilder.ToString() : string.Empty;

				tagA.InnerHtml = string.Concat(cursorPart, sortLinkContentBuilder.ToString());

				resultLinks.Append(tagA.ToString());

				if (enumIndex != sortFieldNames.Length - 1)
				{
					resultLinks.Append(string.Concat(SPACE_STRING, FILTER_LINKS_SEPARATOR, SPACE_STRING));
				}
			}

			return new MvcHtmlString(resultLinks.ToString());
		}

		/// <summary>
		/// Generates mail link.
		/// </summary>
		/// <param name="html">The extension class.</param>
		/// <param name="email">The email, which links will be generated.</param>
		/// <returns>The html string, which contains mail link.</returns>
		public static MvcHtmlString GenerateMailto(this HtmlHelper html, string email)
		{
			TagBuilder tagA = new TagBuilder("a");

			tagA.MergeAttribute(HREF_ATTRIBUTE_NAME, string.Concat("mailto:", email));
			tagA.SetInnerText(email);

			return new MvcHtmlString(tagA.ToString());
		}

		/// <summary>
		/// Generates generic tooltip's message.
		/// </summary>
		/// <param name="html">The extension object.</param>
		/// <param name="tooltipType">The tooltip's type.</param>
		/// <returns>The string, which contains generic tooltip's message.</returns>
		public static string GenerateGenericTooltipMessage(this HtmlHelper html, TooltipType tooltipType)
		{
			string message = string.Empty;

			switch (tooltipType)
			{
				case TooltipType.Add:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_ADD_NEW;
					break;
				case TooltipType.DeleteAllInfo:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_DELETE_ALL_PERSON_INFO;
					break;
				case TooltipType.Delete:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_DELETE;
					break;
				case TooltipType.Edit:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_EDIT;
					break;
				case TooltipType.MoveToReader:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_MOVE_TO_READER;
					break;
				case TooltipType.MoveToHistoryList:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_MOVE_TO_HISTORY_LIST;
					break;
				case TooltipType.MoveToWaitingList:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_MOVE_TO_WAITING_LIST;
					break;
				case TooltipType.AddYourselfToWaitingList:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_ADD_YOURSELF_TO_WAITING_LIST;
					break;
				case TooltipType.HaveReadAndReturned:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_HAVE_READ_AND_RETURNED;
					break;
				case TooltipType.Save:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_SAVE;
					break;
				case TooltipType.Cancel:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_CANCEL;
					break;
				case TooltipType.Undo:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_UNDO;
					break;
				case TooltipType.Redo:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_REDO;
					break;
				case TooltipType.UploadFrom:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_UPLOAD_FROM;
					break;
				case TooltipType.PickPerson:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_PICK_PERSON;
					break;
				case TooltipType.RemovePickedPerson:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_REMOVE_PICKED_PERSON;
					break;
				case TooltipType.ChooseTags:
					message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_CHOOSE_TAGS;
					break;

				default: message = TooltipMessages.GENERIC_TOOLTIP_MESSAGE_NOT_FOUND_ACTION;
					break;
			}

			return message;
		}

		/// <summary>
		/// Generates the location string.
		/// </summary>
		/// <param name="html">The extension object.</param>
		/// <param name="personInfoViewModel">The person view model.</param>
		/// <returns>The result string.</returns>
		public static string GenerateLocationString(this HtmlHelper html, PersonInfoViewModel personInfoViewModel)
		{
			StringBuilder resultLocation = new StringBuilder();

			bool hasPreviousPart = false;

			if (!string.IsNullOrEmpty(personInfoViewModel.Country))
			{
				resultLocation.Append(personInfoViewModel.Country);
				hasPreviousPart = true;
			}

			if (!string.IsNullOrEmpty(personInfoViewModel.City))
			{
				if (hasPreviousPart)
				{
					resultLocation.Append(COMMA_STRING);
					resultLocation.Append(SPACE_STRING);
				}

				resultLocation.Append(personInfoViewModel.City);
				hasPreviousPart = true;
			}

			if (!string.IsNullOrEmpty(personInfoViewModel.DeliveryOffice))
			{
				if (hasPreviousPart)
				{
					resultLocation.Append(COMMA_STRING);
					resultLocation.Append(SPACE_STRING);
				}

				resultLocation.Append(personInfoViewModel.DeliveryOffice);
			}

			return resultLocation.ToString();
		}

		#endregion

		/// <summary>
		/// Checks that the application build is debug or not.
		/// </summary>
		/// <param name="htmlHelper">The extension class.</param>
		/// <returns>The result of checking operation.</returns>
		public static bool IsDebug(this HtmlHelper htmlHelper)
		{
			bool isDebug = false;

			#if DEBUG
				isDebug=true;
			#endif

			return isDebug;
		}

		#region Private Fields

		/// <summary>
		/// Appends pages to the current pages builder.
		/// </summary>
		/// <param name="startPage">The start page.</param>
		/// <param name="endPage">The end page.</param>
		/// <param name="currentPage">The current requested page.</param>
		/// <param name="pagesTotal">The total number of requested page.</param>
		/// <param name="pagesBuilder">The current page builder.</param>
		/// <param name="pageUrl">The correct page url generator.</param>
		private static void AppendPages(int startPage, int endPage, int currentPage, int pagesTotal, StringBuilder pagesBuilder, Func<int, string> pageUrl)
		{
			TagBuilder tagA = new TagBuilder(TAG_NAME_A);

			for (int currentDisplayingPage = startPage; currentDisplayingPage <= endPage; currentDisplayingPage++)
			{
				tagA.Attributes.Clear();

				tagA.Attributes.Add(HREF_ATTRIBUTE_NAME, pageUrl(currentDisplayingPage));
				tagA.InnerHtml = currentDisplayingPage.ToString(CultureInfo.InvariantCulture);

				if (currentDisplayingPage == currentPage)
				{
					tagA.AddCssClass(CSS_CLASS_SELECTED);
				}

				pagesBuilder.AppendLine(tagA.ToString());
			}
		}

		/// <summary>
		/// Generates cursor icon container.
		/// </summary>
		/// <param name="sortType">The type of sorting.</param>
		/// <returns>The icon container.</returns>
		private static TagBuilder GenerateCursorIcon(SortType sortType)
		{
			TagBuilder tagSpan=new TagBuilder(TAG_NAME_SPAN);

			tagSpan.AddCssClass(CSS_CLASS_ICON);
			tagSpan.AddCssClass(CSS_CLASS_SORT_CURSOR);

			switch (sortType)
			{
				case SortType.Desc:
					{
						tagSpan.AddCssClass(CSS_CLASS_DOWN_SORT_CURSOR);

						break;
					}
				case SortType.Asc:
					{
						tagSpan.AddCssClass(CSS_CLASS_UP_SORT_CURSOR);

						break;
					}
			}

			return tagSpan;
		}

		#endregion
	}
}